<?php


namespace App\Application\Services\App;


use App\Application\Services\BaseService;
use App\Commons\WechatOpenPlatform\WechatOpenPlatformTool;
use App\Exceptions\BaseException;
use App\Models\App\AppProject;
use App\Repositories\App\AppProjectRepository;
use App\Repositories\Wechat\MiniProgramTemplateRepository;

class ProjectService extends BaseService {
    /**
     * 获取应用下的项目分页
     * @return mixed
     */
    public function projectPage() {
        $authApplicationId = $this->getAuthApplicationId();
        
        return AppProjectRepository::getInstance()->queryByConditionAndPage(function ($query) use ($authApplicationId) {
            $query->where('application_id', $authApplicationId);
        });
    }
    
    /**
     * 新建项目
     *
     * @param $data
     * @param $fillAble
     *
     * @return \Illuminate\Database\Eloquent\Model
     * @throws \Exception
     */
    public function projectStore($data, $fillAble) {
        //继承代码模板的域名配置和审核项列表
        $templateEl = MiniProgramTemplateRepository::getInstance()->findItemElById(
            $data['mpt_id'],
            new BaseException(422, 200, "模板不存在")
        );
    
        $extDataInfo = [
            'server_domain'             => array_map(
                function ($val) {
                    return [];
                },
                $templateEl->server_domain
            ),
            'webviewdomain'             => [],
            'wx_submit_audit_item_list' => $templateEl->wx_submit_audit_item_list,

            'application_id'      => $this->getAuthApplicationId(),
            'app_project_type_id' => $templateEl->app_project_type_id,
        ];
        $data         = array_merge($data, $extDataInfo);
        $fillAble     = array_merge($fillAble, array_keys($extDataInfo));
        
        $projectEl = AppProjectRepository::getInstance()->store($data, $fillAble);
        
        return $this->getProjectItemElById($projectEl->id);//获取完整信息
    }
    
    /**
     * @param      $id
     * @param bool $isThrowException
     *
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model|null
     * @throws \Exception
     */
    public function getProjectItemElById($id, $where = [], $isThrowException = true) {
        $authApplicationId = $this->getAuthApplicationId();
        $appProject = AppProjectRepository::getInstance()->getProjectByIdAndApplicationId($id, $authApplicationId, $where);
        
        if ($isThrowException && is_null($appProject)) {
            throw new BaseException(422, 200, "项目不存在");
        }
    
        return $appProject;
    }
    
    /**
     * 获取指定项目授权地址
     *
     * @param $id
     *
     * @return array
     * @throws \Exception
     */
    public function getAuthLoginPageUrl($id) {
        AppProjectRepository::getInstance()->findItemElById($id, new BaseException(422, 200, "项目不存在"));
        $param          = [
            'id' => $id,
        ];
        $callbackUrl    = config('app.url') . '/api/open/wechat/authorization-callback?' . http_build_query($param);
        $projectAuthUrl = WechatOpenPlatformTool::getInstance()->getComponentLoginPageUrl($callbackUrl);
        $returnResult   = [
            'id'                       => $id,
            'callback_url'             => $callbackUrl,
            'component_login_page_url' => $projectAuthUrl,
        ];
        
        //跳转html组织
        $htmlContentList = [
            "<html><body>",
            "<script>window.location.href = '{$projectAuthUrl}';</script>",
            "</body></html>",
        ];
        echo implode('', $htmlContentList);
        exit;
        
        return $returnResult;
    }
    
    /**
     * 上传代码
     * @param $id
     *
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \Exception
     */
    public function codeCommit($id){
        return self::miniProgramCodeCommitByProjectEl($this->getProjectItemElById($id));
    }
    
    /**
     * 上传小程序代码
     *
     * @param      $projectEl
     * @param null $miniProgramTool
     *
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws ProjectException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    public static function miniProgramCodeCommitByProjectEl($projectEl, $miniProgramTool = null) {
        //检测是否授权了小程序
        if ($projectEl->auth_status == AppProject::AUTH_STATUS_NO) {
            throw new BaseException(422, 200, "项目未授权");
        }
        
        $templateId  = $projectEl->miniProgramTemplate->wx_template_id;
        $version     = $projectEl->miniProgramTemplate->wx_user_version;
        $description = $projectEl->miniProgramTemplate->wx_user_desc;
        
        //extJson组织
        $extJson = array_replace_recursive(
            WechatOpenPlatformTool::getOpenPlatformConfigWechatMiniProgramCommonExtJson(),
            [
                'ext' => [
                    'open_appid'                      => $projectEl->open_appid,
                    'open_wx_authorizer_appid'        => $projectEl->wx_authorizer_appid,
                    'open_commit_at'                  => date('Y-m-d H:i:s'),
                    'open_commit_version'             => $version,
                    'open_commit_template_id'         => $templateId,
                    'open_commit_description'         => $description,
                    'open_commit_template_created_at' => $projectEl->miniProgramTemplate->wx_created_at,
                ],
            ],
            $projectEl->appProjectType->ext_json,
            $projectEl->miniProgramTemplate->ext_json,
            $projectEl->ext_json
        );
        
        is_null($miniProgramTool) && ($miniProgramTool = self::getMiniProgramToolByProjectEl($projectEl));
        
        //上传代码
        $commitResult = $miniProgramTool->miniProgramTemplateCommit($templateId, json_encode($extJson), $version, $description);
        
        return [
            'ext_json'      => $extJson,
            'commit_result' => $commitResult,
        ];
    }
    
    /**
     * @param $projectEl
     *
     * @return \App\Commons\WechatOpenPlatform\WechatOpenPlatformMiniProgramTool
     */
    public static function getMiniProgramToolByProjectEl($projectEl) {
        return WechatOpenPlatformTool::getInstance()
            ->getMiniProgramTool($projectEl->wx_authorizer_appid, $projectEl->wx_authorizer_refresh_token, $projectEl);
    }
    
    /**
     * 小程序提交审核
     * @param $id
     *
     * @return array
     * @throws \Exception
     */
    public function miniProgramSubmitAudit($id){
        return self::miniProgramSubmitAuditByProjectEl($this->getProjectItemElById($id));
    }
    
    /**
     * 小程序提交审核,在调用上传代码接口为小程序上传代码后，可以调用本接口，将上传的代码提交审核。
     *
     * @param      $projectEl
     * @param null $miniProgramTool
     *
     * @return array
     * @throws \Exception
     */
    public static function miniProgramSubmitAuditByProjectEl($projectEl, $miniProgramTool = null) {
        //检测是否授权了小程序
        if ($projectEl->auth_status == AppProject::AUTH_STATUS_NO) {
            throw new BaseException(422, 200, "项目未授权");
        }
        
        is_null($miniProgramTool) && ($miniProgramTool = self::getMiniProgramToolByProjectEl($projectEl));
        
        //提交审核,注意：这里 有正在提交审核 的会有异常抛出
        $itemList          = $projectEl->wx_submit_audit_item_rely_mpt ? $projectEl->miniProgramTemplate->wx_submit_audit_item_list : $projectEl->wx_submit_audit_item_list;
        $submitAuditResult = $miniProgramTool->miniProgramSubmitAudit($itemList);
        
        $projectEl->last_audit_status = AppProject::LAST_AUDIT_STATUS_WAITING;
        $projectEl->save();
        
        return [
            'item_list'           => $itemList,
            'submit_audit_result' => $submitAuditResult,
        ];
    }
    
    /**
     * 发布已通过审核的小程序
     *
     * @param $id
     *
     * @return mixed
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    public function miniProgramRelease($id) {
        return self::getMiniProgramToolByProjectEl($this->getProjectItemElById($id))->release();
    }
    
    /**
     * 更新项目
     *
     * @param $id
     * @param $data
     * @param $fillAble
     *
     * @return \Illuminate\Database\Eloquent\Model|mixed
     * @throws \Exception
     */
    public function projectUpdate($id, $data, $fillAble) {
        $projectEl = $this->getProjectItemElById($id);
    
        if (empty($data)) {
            return $projectEl;
        }
        
        //如果模板被修改
        if(isset($data['mpt_id']) && $projectEl->mpt_id != $data['mpt_id']){
            //继承代码模板的域名配置和审核项列表
            $templateEl = MiniProgramTemplateRepository::getInstance()->findItemElById(
                $data['mpt_id'],
                new BaseException(422, 200, "指定模板不存在")
            );
            
            $extDataInfo = [
                'wx_submit_audit_item_list' => $templateEl->wx_submit_audit_item_list,
        
                'app_project_type_id' => $templateEl->app_project_type_id,
            ];
    
            $data         = array_merge($data, $extDataInfo);
            $fillAble     = array_merge($fillAble, array_keys($extDataInfo));
        }
        
        $projectEl = $projectEl->fillable($fillAble)->fill($data);
        $projectEl->save();
        
        return $projectEl;
    }
    
    /**
     * 小程序发布处理
     *
     * @param $id
     *
     * @return null
     * @throws \Exception
     */
    public function publishMiniProgram($id) {
        $projectEl = $this->getProjectItemElById($id);
        $this->checkProjectIsAuth($projectEl);
        $projectEl->load(['appProjectType', 'miniProgramTemplate']);
        
        return self::publishMiniProgramByProjectEl($projectEl);
    }
    
    /**
     * 执行项目 上传小程序代码并提交审核
     *
     * @param $projectEl
     *
     * @return array
     * @throws \Exception
     */
    public static function publishMiniProgramByProjectEl($projectEl) {
        $miniProgramTool   = self::getMiniProgramToolByProjectEl($projectEl);
        $commitResult      = self::miniProgramCodeCommitByProjectEl($projectEl, $miniProgramTool);
        $submitAuditResult = self::miniProgramSubmitAuditByProjectEl($projectEl, $miniProgramTool);
        
        return $commitResult + $submitAuditResult;
    }
    
    /**
     * 获取体验版二维码
     *
     * @param $id
     *
     * @return \EasyWeChat\Kernel\Http\Response|mixed
     * @throws \Exception
     */
    public function getExperienceQrCode($id) {
        $projectEl = $this->getProjectItemElById($id);
        $this->checkProjectIsAuth($projectEl);
        
        return self::getMiniProgramToolByProjectEl($projectEl)->getQrCode();
    }
    
    /**
     * 检测项目是否授权
     *
     * @param      $projectEl
     * @param bool $isThrowException
     *
     * @return bool
     * @throws BaseException
     */
    protected function checkProjectIsAuth($projectEl, $isThrowException = true) {
        $checkResult = $projectEl['auth_status'] == AppProject::AUTH_STATUS_YES;
        
        if ($isThrowException && !$checkResult) {
            throw new BaseException(422, 200, "小程序未授权");
        }
        
        return $checkResult;
    }
}